package com.atguigu.gmall.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.IpUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * @author atguigu-mqx
 */
@Component
public class AuthGlobalFilter implements GlobalFilter {

    //  这里需要引入缓存！
    @Autowired
    private RedisTemplate redisTemplate;

    @Value("${authUrls.url}")
    private String authUrls;

    private AntPathMatcher matcher = new AntPathMatcher();
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //  获取到用户的请求路径！
        //  http://item.gmall.com/api/product/inner/getSkuInfo/23
        //  获取到请求对象
        ServerHttpRequest request = exchange.getRequest();
        //  path = api/product/inner/getSkuInfo/23
        String path = request.getURI().getPath();
        //  判断这个path 第一个参数：符合什么样的格式 第二个参数：整体的url
        if (matcher.match("/**/inner/**",path)){
            //  如果符合这样的格式，则提示用户没有权限访问！
            ServerHttpResponse response = exchange.getResponse();
            //  提示用户信息！
            return out(response, ResultCodeEnum.PERMISSION);
        }

        //  需要获取用户Id; 用户Id 是存储在缓存中的！ key=user:token;
        String userId = getUserId(request);
        String userTempId = getUserTempId(request);
        //  需要做个判断：防止用户的token 被盗用！
        if ("-1".equals(userId)){
            //  token 不匹配！
            //  如果符合这样的格式，则提示用户没有权限访问！
            ServerHttpResponse response = exchange.getResponse();
            //  提示用户信息！
            return out(response, ResultCodeEnum.PERMISSION);
        }
        //  限制用户访问带有 auth 这样的url 地址！
        if (matcher.match("/api/**/auth/**",path)){
            //  前提是用户未登录，不能访问！
            if (StringUtils.isEmpty(userId)){
                //  如果符合这样的格式，则提示用户没有登录访问！
                ServerHttpResponse response = exchange.getResponse();
                //  提示用户信息！
                return out(response, ResultCodeEnum.LOGIN_AUTH);
            }
        }

        //  限制用户访问 web-all 中 trade.html,myOrder.html,list.html
        String[] split = authUrls.split(",");
        if (split!=null && split.length>0){
            //  循环遍历
            for (String url : split) {
                //  判断 path 中如果包含 trade.html,myOrder.html,list.html 其中之一就需要跳转到登录页面！
                //  前提是用户未登录的情况下，包含其中之一就跳转！
                if (path.indexOf(url)!=-1 && StringUtils.isEmpty(userId)){
                    //  如果符合这样的格式，则跳转到登录页面！
                    ServerHttpResponse response = exchange.getResponse();
                    //  设置状态码！
                    response.setStatusCode(HttpStatus.SEE_OTHER);
                    //  设置地址：
                    //  request.getURI() 用户请求的完整路径  http://passport.gmall.com/login.html?originUrl=http://www.gmall.com/
                    //  request.getURI().getPath()  login.html?originUrl=http://www.gmall.com/
                    response.getHeaders().set(HttpHeaders.LOCATION,"http://passport.gmall.com/login.html?originUrl="+request.getURI());
                    //  重定向到登录页面！
                    return response.setComplete();
                }
            }
        }
        //  将用户Id 放入请求头
        if (!StringUtils.isEmpty(userId) || !StringUtils.isEmpty(userTempId)){
            if (!StringUtils.isEmpty(userId)){
                //  设置请求头 ServerHttpRequest
                request.mutate().header("userId", userId).build();
            }
            if (!StringUtils.isEmpty(userTempId)){
                //  设置请求头 ServerHttpRequest
                request.mutate().header("userTempId", userTempId).build();
            }
            //  返回数据 可以将request 变为 exchange！
            return chain.filter(exchange.mutate().request(request).build());
        }
        //  默认返回
        return chain.filter(exchange);
    }

    /**
     * 获取临时用户Id
     * @param request
     * @return
     */
    private String getUserTempId(ServerHttpRequest request) {
        String userTempId = "";
        HttpCookie httpCookie = request.getCookies().getFirst("userTempId");
        if (httpCookie!=null){
            //  获取 cookie 中的数据！
            userTempId = httpCookie.getValue();
        }else {
            List<String> stringList = request.getHeaders().get("userTempId");
            if (!CollectionUtils.isEmpty(stringList)){
                userTempId = stringList.get(0);
            }
        }
        //  获取临时用户Id
        return userTempId;
    }

    /**
     * 获取用户Id
     * @param request
     * @return
     */
    private String getUserId(ServerHttpRequest request) {
        //  从cookie 中或者从 header中获取
        String token = "";
        HttpCookie httpCookie = request.getCookies().getFirst("token");
        if (httpCookie!=null){
            //  获取 cookie 中的数据！
            token = httpCookie.getValue();
        }else {
            List<String> stringList = request.getHeaders().get("token");
            if (!CollectionUtils.isEmpty(stringList)){
                token = stringList.get(0);
            }
        }
        //  判断token
        if (!StringUtils.isEmpty(token)){
            //  才能从缓存中获取数据！
            String userLoginKey = "user:login:"+token;
            //  从缓存中获取数据
            String strJson = (String) this.redisTemplate.opsForValue().get(userLoginKey);
            //  需要将这个字符串转换为对象！ JSONObject
            JSONObject userJson = JSONObject.parseObject(strJson);
            //  获取里面的数据
            String ip = (String) userJson.get("ip");
            //  判断ip 相等
            if (ip.equals(IpUtil.getGatwayIpAddress(request))){
                  String userId = (String) userJson.get("userId");
                  return userId;
            }else {
                return "-1";
            }
        }
        return "";
    }

    /**
     * 用户信息提示
     * @param response
     * @param resultCodeEnum
     * @return
     */
    private Mono<Void> out(ServerHttpResponse response, ResultCodeEnum resultCodeEnum) {
        //  需要将resultCodeEnum 这个对象转换一下！ ResultCodeEnum ---> result
        Result result = Result.build(null,resultCodeEnum);
        //  输入数据 result 变成字符串！
        //  JSON.toJSONString(result).getBytes(StandardCharsets.UTF_8);
        byte[] bytes = JSON.toJSONString(result).getBytes();
        DataBuffer wrap = response.bufferFactory().wrap(bytes);// byte[] var1
        //  设置输入的页面时的格式！
        response.getHeaders().add("Content-Type","application/json;charset=UTF-8");
        //  Publisher<? extends DataBuffer> var1
        return response.writeWith(Mono.just(wrap));
    }
}
